Objective

The aim of this section is to present the different widgets used for the exploration of hypercubes and developped during the ODYCCEUS project. We adapt a little the initial programs for the case of octocubes that are used in IMAGEUN but the principles remains the same. Each widget will export a dataframe and a plotly figure, making possible to store the results in javascript and/or to use the table for development with another software.

Preparation

Load multilevel octocubes and transform in hypercubes

We load the octocubes at different levels of time agregation and transform them in hypercubes by removing the dual dimensions of states and regions

base<-readRDS("octocubes/hc_mycorpus_covid_states_regions.RDS")
hc_day<-base$day[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]
hc_week<-base$week[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]
hc_month<-base$month[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]
hc_year<-base$year[,.(tag=sum(tags),news=sum(news)),.(who,what,when,states=states1,regions=regions1)]

Load statistical test function

#### ---------------- testchi2 ----------------
#' @title  Compute the average salience of the topic and test significance of deviation
#' @name what
#' @description create a table and graphic of the topic
#' @param tabtest a table with variable trial, success and null.value
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest : Threshold of estimated value requested for chi-square test


testchi2<-function(tabtest=tabtest,
                   minsamp = 20,
                   mintest = 5) 
{
  tab<-tabtest
  n<-dim(tab)[1]
  
  # Compute salience if sample size sufficient (default : N>20)
  tab$estimate <-NA
  tab$salience <-NA
  tab$chi2<-NA
  tab$p.value<-NA
   tab$estimate<-round(tab$success/tab$trial,5)
   tab$salience<-tab$estimate/tab$null.value
  
  # Chi-square test if estimated value sufficient (default : Nij* > 5)
  
  for (i in 1:n) {
    if(tab$trial[i]*tab$null.value[i]>=mintest) {  
      test<-prop.test(x=tab$success[i],n=tab$trial[i], p=tab$null.value[i], 
                      alternative = "greater")
      tab$chi2[i]<-round(test$statistic,2)
      tab$p.value[i]<-round(test$p.value,5)
    } 
  }
 # }
  return(tab)
}

What

Function

### ---------------- what ----------------
#' @title  Compute the average salience of the topic
#' @name what
#' @description create a table and graphic of the topic
#' @param hc an hypercube prepared as data.table
#' @param subtop a subtag of the main tag (default = NA)
#' @param title Title of the graphic


what <- function (hc = hypercube,
                  what = "what",
                  subtop = NA,
                  title = "What ?")
{
 
  
tab<-hc
tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}

tab<-tab[,list(news = sum(news)),by = what]
tab$pct<-100*tab$news/sum(tab$news)

p <- plot_ly(tab,
             labels = ~what,
             values = ~pct,
             type = 'pie') %>%
  layout(title = title,
         xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
         yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))

output<-list("table" = tab, "plotly" =p)

return(output)

}

Application 1 : covid topic

res<-what(hc_year)
res$table
res$plotly

Application n°2 : state subtopic

res <-hc_year %>% filter(states != "_no_") %>%
what(what = "states",
     subtop ="RUS",
     title = "Share of Russia in international news")
res$table
res$plotly

Application n°3 : macroregion subtopic

res <-hc_year %>% filter(regions != "_no_") %>%
what(what = "regions",
     subtop ="OR_EU",
     title = "Share of EU in macroregional news")
res$table
res$plotly

Who.What

function

#### ---------------- who.what ----------------
#' @title  visualize variation of the topic between media
#' @name who.what
#' @description create a table of variation of the topic by media
#' @param hc an hypercube prepared as data.table
#' @param test : visualize test (TRUE) or salience (FALSE)
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest sample size of estimate for chi-square test (default = 5)
#' @param title Title of the graphic


who.what <- function (hc = hypercube,
                      what = "what",
                      subtop = NA,
                      test = FALSE,
                      minsamp = 20,
                      mintest = 5,
                      title = "Who says What ?")
{
  
  tab<-hc
  tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}
#  {tab$what <-tab$what !="_no_"}
  
  tab<-tab[,list(trial = sum(news),success=round(sum(news*what),0)),by = list(who)]
  ref <-round(sum(tab$success)/sum(tab$trial),4)
  tab$null.value<-ref
  
  tab<-testchi2(tabtest=tab,
                minsamp = minsamp,
                mintest = mintest)
  
  
  
  if (test==FALSE) {tab$index =tab$salience
  tab$index[tab$index>4]<-4
  tab<-tab[tab$trial > minsamp,]
  mycol<-brewer.pal(7,"YlOrRd")
  } 
  else {tab$index=1-tab$p.value
  tab<-tab[tab$trial*tab$null.value>mintest,]
  mycol<-rev(brewer.pal(7,"RdYlBu"))
  mycol[4]<-"lightyellow"
  }
  
  p <- plot_ly(tab,
               x = ~who,
               y = ~estimate*100,
               color= ~index,
               colors= mycol,
               hovertemplate = ~paste('Source: ',who,
                             '<br /> Total news  : ', round(trial,0),
                             '<br /> Topic news : ', round(success,0),
                             '<br /> % observed  : ', round(estimate*100,2),'%',
                             '<br /> % estimated : ', round(null.value*100,2),'%',
                             '<br /> Salience : ', round(salience,2),  
                             '<br /> p.value : ', round(p.value,4)),
               type = "bar")  %>%
    layout(title = title,
           yaxis = list(title = "% news"),
           barmode = 'stack')
  
  output<-list("table" = tab, "plotly" =p)
  
  return(output)
  
}

Applicaton n°1 : Covid Topic

An example of computation of the share of a non spatial topic (Covid) in the full sample of news.

res <- hc_year %>%
who.what(what = "what",
     title = "Share of Covid in total news",
     test=FALSE)

res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays

Application n°2 : State subtopic

An example of computation of the share of a national subtopic (Russia) in the sample of news where the topic is present (news with at least one state mentionned).

res <-hc_year %>% filter(states != "_no_") %>%
who.what(what = "states",
     subtop ="RUS",
     title = "Share of Russia in international news",
     test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays

Application n°3 : Macroregion subtopic

Same example applied to macroregion : what is the share of the subtopic European Union in the subsample news where at least one macroregion is mentionned.

res <-hc_year %>% filter(regions != "_no_") %>%
who.what(what = "regions",
     subtop ="OR_EU",
     title = "Share of EU in macroregional news",
     test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
saveWidget(widget=res$plotly,
           file = "widgets/widget_who_what.html",
           selfcontained = T,
           libdir="lib")
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays

When.What

function


#### ---------------- when.what ----------------
#' @title  visualize variation of the topic through time
#' @name when.what
#' @description create a table of variation of the topic by media
#' @param test : visualize test (TRUE) or salience (FALSE)
#' @param minsamp : Threshold of sample size requested for salience computation
#' @param mintest sample size of estimate for chi-square test (default = 5)
#' @param title Title of the graphic


when.what <- function (hc = hypercube,
                       what = "what",
                       subtop = NA,
                       test = FALSE,
                       minsamp = 20,
                       mintest = 5,
                       title = "When is said What ?")
{
  
  tab<-hc
  tab$what<-tab[[what]]
if (is.na(subtop)){tab$what <-tab$what !="_no_"}else {tab$what <- tab$what == subtop}
#  {tab$what <-tab$what !="_no_"}
  
  tab<-tab[,list(trial = sum(news),success=round(sum(news*what),0)),by = list(when)]
  ref <-round(sum(tab$success)/sum(tab$trial),4)
  tab$null.value<-ref
  
  tab<-testchi2(tabtest=tab,
                minsamp = minsamp,
                mintest = mintest)
  
  if (test==FALSE) {tab$index =tab$salience
  tab<-tab[tab$trial > minsamp,]
  mycol<-brewer.pal(7,"YlOrRd")
  } 
  else {tab$index=tab$p.value
  tab<-tab[tab$trial*tab$null.value>mintest,]
  mycol<-brewer.pal(7,"RdYlBu")
  mycol[4]<-"lightyellow"
  }
  
  
  p <- plot_ly(tab,
               x = ~as.character(when),
               y = ~estimate*100,
               color= ~index,
               colors= mycol,
     #          hoverinfo = "text",
               hovertemplate = ~paste('Time: ',when,
                             '<br /> Total news  : ', round(trial,0),
                             '<br /> Topic news : ', round(success,0),
                             '<br /> % observed  : ', round(estimate*100,2),'%',
                             '<br /> % estimated : ', round(null.value*100,2),'%',
                             '<br /> Salience : ', round(salience,2),  
                             '<br /> p.value : ', round(p.value,4)),
               type = "bar")  %>%
    layout(title = title,
           yaxis = list(title = "% news"),
           barmode = 'stack')
  
  output<-list("table" = tab, "plotly" =p)
  
  return(output)
  
}

Applicaton n°1 : Covid Topic

An example of computation of the share of a non spatial topic (Covid) in the full sample of news by week for one media.

res <- hc_week %>% filter(who=="DEU_suddeu") %>%
when.what(what = "what",
     title = "Share of Covid-19 topic in news published by Süddeutsche Zeitung",
     test=FALSE)

res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays

Application n°2 : State subtopic

Example of analysis of the share of news about Russia among news mentionning one country, by month, for Le Figaro.

res <-hc_month %>% filter(states != "_no_") %>%  filter(who=="FRA_figaro") %>%
when.what(what = "states",
     subtop ="RUS",
     title = "Share of Russia in international news published by Le Figaro",
     test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays

Application n°3 : Macroregion subtopic

Example of analysis of the share of news about European news among news mentioning one macroregion, by year, for Dunya.

res <-hc_year %>% filter(regions != "_no_") %>%  filter(who=="TUR_dunya") %>%
when.what(what = "regions",
     subtop ="OR_EU",
     title = "Share of EU in macroregional news published by Dunya",
     test=TRUE)
res$table
res$plotly
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
saveWidget(widget=res$plotly,
           file = "widgets/widget_who_what.html",
           selfcontained = T,
           libdir="lib")
Warning: textfont.color doesn't (yet) support data arraysWarning: textfont.color doesn't (yet) support data arrays
LS0tCnRpdGxlOiAiR2VvZ3JhcGhpY2FsIGFuYWx5c2lzIG9mIG1lZGlhIgpzdWJ0aXRsZTogIjUuIFdpZGdldHMiCmF1dGhvcjogIkNsYXVkZSBHcmFzbGFuZCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyIHNldHVwNSwgZWNobyA9IEZBTFNFLCBjb21tZW50ID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNvbW1lbnQgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShSQ29sb3JCcmV3ZXIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShrbml0cikKbGlicmFyeShodG1sd2lkZ2V0cykKI2xpYnJhcnkodGlkeWdyYXBoKQojbGlicmFyeShnZ3JhcGgpCiNsaWJyYXJ5KHZpc05ldHdvcmspCmBgYAoKCgojIyBPYmplY3RpdmUKClRoZSBhaW0gb2YgdGhpcyBzZWN0aW9uIGlzIHRvIHByZXNlbnQgdGhlIGRpZmZlcmVudCB3aWRnZXRzIHVzZWQgZm9yIHRoZSBleHBsb3JhdGlvbiBvZiBoeXBlcmN1YmVzIGFuZCBkZXZlbG9wcGVkIGR1cmluZyB0aGUgT0RZQ0NFVVMgcHJvamVjdC4gV2UgYWRhcHQgYSBsaXR0bGUgdGhlIGluaXRpYWwgcHJvZ3JhbXMgZm9yIHRoZSBjYXNlIG9mIG9jdG9jdWJlcyB0aGF0IGFyZSB1c2VkIGluIElNQUdFVU4gYnV0IHRoZSBwcmluY2lwbGVzIHJlbWFpbnMgdGhlIHNhbWUuIEVhY2ggd2lkZ2V0IHdpbGwgZXhwb3J0IGEgZGF0YWZyYW1lIGFuZCBhIHBsb3RseSBmaWd1cmUsIG1ha2luZyBwb3NzaWJsZSB0byBzdG9yZSB0aGUgcmVzdWx0cyBpbiBqYXZhc2NyaXB0IGFuZC9vciB0byB1c2UgdGhlIHRhYmxlIGZvciBkZXZlbG9wbWVudCB3aXRoIGFub3RoZXIgc29mdHdhcmUuCgoKCiMjIFByZXBhcmF0aW9uCgojIyMgTG9hZCBtdWx0aWxldmVsIG9jdG9jdWJlcyBhbmQgdHJhbnNmb3JtIGluIGh5cGVyY3ViZXMKCldlIGxvYWQgdGhlIG9jdG9jdWJlcyBhdCBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRpbWUgYWdyZWdhdGlvbiBhbmQgdHJhbnNmb3JtIHRoZW0gaW4gaHlwZXJjdWJlcyBieSByZW1vdmluZyB0aGUgZHVhbCBkaW1lbnNpb25zIG9mIHN0YXRlcyBhbmQgcmVnaW9ucwoKYGBge3J9CmJhc2U8LXJlYWRSRFMoIm9jdG9jdWJlcy9oY19teWNvcnB1c19jb3ZpZF9zdGF0ZXNfcmVnaW9ucy5SRFMiKQpoY19kYXk8LWJhc2UkZGF5WywuKHRhZz1zdW0odGFncyksbmV3cz1zdW0obmV3cykpLC4od2hvLHdoYXQsd2hlbixzdGF0ZXM9c3RhdGVzMSxyZWdpb25zPXJlZ2lvbnMxKV0KaGNfd2VlazwtYmFzZSR3ZWVrWywuKHRhZz1zdW0odGFncyksbmV3cz1zdW0obmV3cykpLC4od2hvLHdoYXQsd2hlbixzdGF0ZXM9c3RhdGVzMSxyZWdpb25zPXJlZ2lvbnMxKV0KaGNfbW9udGg8LWJhc2UkbW9udGhbLC4odGFnPXN1bSh0YWdzKSxuZXdzPXN1bShuZXdzKSksLih3aG8sd2hhdCx3aGVuLHN0YXRlcz1zdGF0ZXMxLHJlZ2lvbnM9cmVnaW9uczEpXQpoY195ZWFyPC1iYXNlJHllYXJbLC4odGFnPXN1bSh0YWdzKSxuZXdzPXN1bShuZXdzKSksLih3aG8sd2hhdCx3aGVuLHN0YXRlcz1zdGF0ZXMxLHJlZ2lvbnM9cmVnaW9uczEpXQpgYGAKCgojIyMgTG9hZCBzdGF0aXN0aWNhbCB0ZXN0IGZ1bmN0aW9uCgpgYGB7cn0KIyMjIyAtLS0tLS0tLS0tLS0tLS0tIHRlc3RjaGkyIC0tLS0tLS0tLS0tLS0tLS0KIycgQHRpdGxlICBDb21wdXRlIHRoZSBhdmVyYWdlIHNhbGllbmNlIG9mIHRoZSB0b3BpYyBhbmQgdGVzdCBzaWduaWZpY2FuY2Ugb2YgZGV2aWF0aW9uCiMnIEBuYW1lIHdoYXQKIycgQGRlc2NyaXB0aW9uIGNyZWF0ZSBhIHRhYmxlIGFuZCBncmFwaGljIG9mIHRoZSB0b3BpYwojJyBAcGFyYW0gdGFidGVzdCBhIHRhYmxlIHdpdGggdmFyaWFibGUgdHJpYWwsIHN1Y2Nlc3MgYW5kIG51bGwudmFsdWUKIycgQHBhcmFtIG1pbnNhbXAgOiBUaHJlc2hvbGQgb2Ygc2FtcGxlIHNpemUgcmVxdWVzdGVkIGZvciBzYWxpZW5jZSBjb21wdXRhdGlvbgojJyBAcGFyYW0gbWludGVzdCA6IFRocmVzaG9sZCBvZiBlc3RpbWF0ZWQgdmFsdWUgcmVxdWVzdGVkIGZvciBjaGktc3F1YXJlIHRlc3QKCgp0ZXN0Y2hpMjwtZnVuY3Rpb24odGFidGVzdD10YWJ0ZXN0LAogICAgICAgICAgICAgICAgICAgbWluc2FtcCA9IDIwLAogICAgICAgICAgICAgICAgICAgbWludGVzdCA9IDUpIAp7CiAgdGFiPC10YWJ0ZXN0CiAgbjwtZGltKHRhYilbMV0KICAKICAjIENvbXB1dGUgc2FsaWVuY2UgaWYgc2FtcGxlIHNpemUgc3VmZmljaWVudCAoZGVmYXVsdCA6IE4+MjApCiAgdGFiJGVzdGltYXRlIDwtTkEKICB0YWIkc2FsaWVuY2UgPC1OQQogIHRhYiRjaGkyPC1OQQogIHRhYiRwLnZhbHVlPC1OQQogICB0YWIkZXN0aW1hdGU8LXJvdW5kKHRhYiRzdWNjZXNzL3RhYiR0cmlhbCw1KQogICB0YWIkc2FsaWVuY2U8LXRhYiRlc3RpbWF0ZS90YWIkbnVsbC52YWx1ZQogIAogICMgQ2hpLXNxdWFyZSB0ZXN0IGlmIGVzdGltYXRlZCB2YWx1ZSBzdWZmaWNpZW50IChkZWZhdWx0IDogTmlqKiA+IDUpCiAgCiAgZm9yIChpIGluIDE6bikgewogICAgaWYodGFiJHRyaWFsW2ldKnRhYiRudWxsLnZhbHVlW2ldPj1taW50ZXN0KSB7ICAKICAgICAgdGVzdDwtcHJvcC50ZXN0KHg9dGFiJHN1Y2Nlc3NbaV0sbj10YWIkdHJpYWxbaV0sIHA9dGFiJG51bGwudmFsdWVbaV0sIAogICAgICAgICAgICAgICAgICAgICAgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpCiAgICAgIHRhYiRjaGkyW2ldPC1yb3VuZCh0ZXN0JHN0YXRpc3RpYywyKQogICAgICB0YWIkcC52YWx1ZVtpXTwtcm91bmQodGVzdCRwLnZhbHVlLDUpCiAgICB9IAogIH0KICMgfQogIHJldHVybih0YWIpCn0KCmBgYAoKIyMgV2hhdAoKCiMjIyBGdW5jdGlvbgoKYGBge3J9CiMjIyAtLS0tLS0tLS0tLS0tLS0tIHdoYXQgLS0tLS0tLS0tLS0tLS0tLQojJyBAdGl0bGUgIENvbXB1dGUgdGhlIGF2ZXJhZ2Ugc2FsaWVuY2Ugb2YgdGhlIHRvcGljCiMnIEBuYW1lIHdoYXQKIycgQGRlc2NyaXB0aW9uIGNyZWF0ZSBhIHRhYmxlIGFuZCBncmFwaGljIG9mIHRoZSB0b3BpYwojJyBAcGFyYW0gaGMgYW4gaHlwZXJjdWJlIHByZXBhcmVkIGFzIGRhdGEudGFibGUKIycgQHBhcmFtIHN1YnRvcCBhIHN1YnRhZyBvZiB0aGUgbWFpbiB0YWcgKGRlZmF1bHQgPSBOQSkKIycgQHBhcmFtIHRpdGxlIFRpdGxlIG9mIHRoZSBncmFwaGljCgoKd2hhdCA8LSBmdW5jdGlvbiAoaGMgPSBoeXBlcmN1YmUsCiAgICAgICAgICAgICAgICAgIHdoYXQgPSAid2hhdCIsCiAgICAgICAgICAgICAgICAgIHN1YnRvcCA9IE5BLAogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJXaGF0ID8iKQp7CiAKICAKdGFiPC1oYwp0YWIkd2hhdDwtdGFiW1t3aGF0XV0KaWYgKGlzLm5hKHN1YnRvcCkpe3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9ZWxzZSB7dGFiJHdoYXQgPC0gdGFiJHdoYXQgPT0gc3VidG9wfQoKdGFiPC10YWJbLGxpc3QobmV3cyA9IHN1bShuZXdzKSksYnkgPSB3aGF0XQp0YWIkcGN0PC0xMDAqdGFiJG5ld3Mvc3VtKHRhYiRuZXdzKQoKcCA8LSBwbG90X2x5KHRhYiwKICAgICAgICAgICAgIGxhYmVscyA9IH53aGF0LAogICAgICAgICAgICAgdmFsdWVzID0gfnBjdCwKICAgICAgICAgICAgIHR5cGUgPSAncGllJykgJT4lCiAgbGF5b3V0KHRpdGxlID0gdGl0bGUsCiAgICAgICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCBzaG93dGlja2xhYmVscyA9IEZBTFNFKSwKICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRkFMU0UsIHNob3d0aWNrbGFiZWxzID0gRkFMU0UpKQoKb3V0cHV0PC1saXN0KCJ0YWJsZSIgPSB0YWIsICJwbG90bHkiID1wKQoKcmV0dXJuKG91dHB1dCkKCn0KYGBgCgojIyMgQXBwbGljYXRpb24gMSA6IGNvdmlkIHRvcGljCgoKYGBge3J9CnJlczwtd2hhdChoY195ZWFyKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgojIyMgQXBwbGljYXRpb24gbsKwMiA6IHN0YXRlIHN1YnRvcGljCgpgYGB7cn0KcmVzIDwtaGNfeWVhciAlPiUgZmlsdGVyKHN0YXRlcyAhPSAiX25vXyIpICU+JQp3aGF0KHdoYXQgPSAic3RhdGVzIiwKICAgICBzdWJ0b3AgPSJSVVMiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIFJ1c3NpYSBpbiBpbnRlcm5hdGlvbmFsIG5ld3MiKQpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCiMjIyBBcHBsaWNhdGlvbiBuwrAzIDogbWFjcm9yZWdpb24gc3VidG9waWMKCmBgYHtyfQpyZXMgPC1oY195ZWFyICU+JSBmaWx0ZXIocmVnaW9ucyAhPSAiX25vXyIpICU+JQp3aGF0KHdoYXQgPSAicmVnaW9ucyIsCiAgICAgc3VidG9wID0iT1JfRVUiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIEVVIGluIG1hY3JvcmVnaW9uYWwgbmV3cyIpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CmBgYAoKIyMgV2hvLldoYXQKCiMjIyBmdW5jdGlvbgoKYGBge3J9CiMjIyMgLS0tLS0tLS0tLS0tLS0tLSB3aG8ud2hhdCAtLS0tLS0tLS0tLS0tLS0tCiMnIEB0aXRsZSAgdmlzdWFsaXplIHZhcmlhdGlvbiBvZiB0aGUgdG9waWMgYmV0d2VlbiBtZWRpYQojJyBAbmFtZSB3aG8ud2hhdAojJyBAZGVzY3JpcHRpb24gY3JlYXRlIGEgdGFibGUgb2YgdmFyaWF0aW9uIG9mIHRoZSB0b3BpYyBieSBtZWRpYQojJyBAcGFyYW0gaGMgYW4gaHlwZXJjdWJlIHByZXBhcmVkIGFzIGRhdGEudGFibGUKIycgQHBhcmFtIHRlc3QgOiB2aXN1YWxpemUgdGVzdCAoVFJVRSkgb3Igc2FsaWVuY2UgKEZBTFNFKQojJyBAcGFyYW0gbWluc2FtcCA6IFRocmVzaG9sZCBvZiBzYW1wbGUgc2l6ZSByZXF1ZXN0ZWQgZm9yIHNhbGllbmNlIGNvbXB1dGF0aW9uCiMnIEBwYXJhbSBtaW50ZXN0IHNhbXBsZSBzaXplIG9mIGVzdGltYXRlIGZvciBjaGktc3F1YXJlIHRlc3QgKGRlZmF1bHQgPSA1KQojJyBAcGFyYW0gdGl0bGUgVGl0bGUgb2YgdGhlIGdyYXBoaWMKCgp3aG8ud2hhdCA8LSBmdW5jdGlvbiAoaGMgPSBoeXBlcmN1YmUsCiAgICAgICAgICAgICAgICAgICAgICB3aGF0ID0gIndoYXQiLAogICAgICAgICAgICAgICAgICAgICAgc3VidG9wID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICB0ZXN0ID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBtaW5zYW1wID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICBtaW50ZXN0ID0gNSwKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIldobyBzYXlzIFdoYXQgPyIpCnsKICAKICB0YWI8LWhjCiAgdGFiJHdoYXQ8LXRhYltbd2hhdF1dCmlmIChpcy5uYShzdWJ0b3ApKXt0YWIkd2hhdCA8LXRhYiR3aGF0ICE9Il9ub18ifWVsc2Uge3RhYiR3aGF0IDwtIHRhYiR3aGF0ID09IHN1YnRvcH0KIyAge3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9CiAgCiAgdGFiPC10YWJbLGxpc3QodHJpYWwgPSBzdW0obmV3cyksc3VjY2Vzcz1yb3VuZChzdW0obmV3cyp3aGF0KSwwKSksYnkgPSBsaXN0KHdobyldCiAgcmVmIDwtcm91bmQoc3VtKHRhYiRzdWNjZXNzKS9zdW0odGFiJHRyaWFsKSw0KQogIHRhYiRudWxsLnZhbHVlPC1yZWYKICAKICB0YWI8LXRlc3RjaGkyKHRhYnRlc3Q9dGFiLAogICAgICAgICAgICAgICAgbWluc2FtcCA9IG1pbnNhbXAsCiAgICAgICAgICAgICAgICBtaW50ZXN0ID0gbWludGVzdCkKICAKICAKICAKICBpZiAodGVzdD09RkFMU0UpIHt0YWIkaW5kZXggPXRhYiRzYWxpZW5jZQogIHRhYiRpbmRleFt0YWIkaW5kZXg+NF08LTQKICB0YWI8LXRhYlt0YWIkdHJpYWwgPiBtaW5zYW1wLF0KICBteWNvbDwtYnJld2VyLnBhbCg3LCJZbE9yUmQiKQogIH0gCiAgZWxzZSB7dGFiJGluZGV4PTEtdGFiJHAudmFsdWUKICB0YWI8LXRhYlt0YWIkdHJpYWwqdGFiJG51bGwudmFsdWU+bWludGVzdCxdCiAgbXljb2w8LXJldihicmV3ZXIucGFsKDcsIlJkWWxCdSIpKQogIG15Y29sWzRdPC0ibGlnaHR5ZWxsb3ciCiAgfQogIAogIHAgPC0gcGxvdF9seSh0YWIsCiAgICAgICAgICAgICAgIHggPSB+d2hvLAogICAgICAgICAgICAgICB5ID0gfmVzdGltYXRlKjEwMCwKICAgICAgICAgICAgICAgY29sb3I9IH5pbmRleCwKICAgICAgICAgICAgICAgY29sb3JzPSBteWNvbCwKICAgICAgICAgICAgICAgaG92ZXJ0ZW1wbGF0ZSA9IH5wYXN0ZSgnU291cmNlOiAnLHdobywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IFRvdGFsIG5ld3MgIDogJywgcm91bmQodHJpYWwsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiBUb3BpYyBuZXdzIDogJywgcm91bmQoc3VjY2VzcywwKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+ICUgb2JzZXJ2ZWQgIDogJywgcm91bmQoZXN0aW1hdGUqMTAwLDIpLCclJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+ICUgZXN0aW1hdGVkIDogJywgcm91bmQobnVsbC52YWx1ZSoxMDAsMiksJyUnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gU2FsaWVuY2UgOiAnLCByb3VuZChzYWxpZW5jZSwyKSwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gcC52YWx1ZSA6ICcsIHJvdW5kKHAudmFsdWUsNCkpLAogICAgICAgICAgICAgICB0eXBlID0gImJhciIpICAlPiUKICAgIGxheW91dCh0aXRsZSA9IHRpdGxlLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIlIG5ld3MiKSwKICAgICAgICAgICBiYXJtb2RlID0gJ3N0YWNrJykKICAKICBvdXRwdXQ8LWxpc3QoInRhYmxlIiA9IHRhYiwgInBsb3RseSIgPXApCiAgCiAgcmV0dXJuKG91dHB1dCkKICAKfQpgYGAKCiMjIyBBcHBsaWNhdG9uIG7CsDEgOiBDb3ZpZCBUb3BpYwoKQW4gZXhhbXBsZSBvZiBjb21wdXRhdGlvbiBvZiB0aGUgc2hhcmUgb2YgYSBub24gc3BhdGlhbCB0b3BpYyAoQ292aWQpIGluIHRoZSBmdWxsIHNhbXBsZSBvZiBuZXdzLgoKYGBge3J9CnJlcyA8LSBoY195ZWFyICU+JQp3aG8ud2hhdCh3aGF0ID0gIndoYXQiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIENvdmlkIGluIHRvdGFsIG5ld3MiLAogICAgIHRlc3Q9RkFMU0UpCgpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgoKIyMjIEFwcGxpY2F0aW9uIG7CsDIgOiBTdGF0ZSBzdWJ0b3BpYwoKQW4gZXhhbXBsZSBvZiBjb21wdXRhdGlvbiBvZiB0aGUgc2hhcmUgb2YgYSBuYXRpb25hbCBzdWJ0b3BpYyAoUnVzc2lhKSBpbiB0aGUgc2FtcGxlIG9mIG5ld3Mgd2hlcmUgdGhlIHRvcGljIGlzIHByZXNlbnQgKG5ld3Mgd2l0aCBhdCBsZWFzdCBvbmUgc3RhdGUgbWVudGlvbm5lZCkuCgpgYGB7cn0KcmVzIDwtaGNfeWVhciAlPiUgZmlsdGVyKHN0YXRlcyAhPSAiX25vXyIpICU+JQp3aG8ud2hhdCh3aGF0ID0gInN0YXRlcyIsCiAgICAgc3VidG9wID0iUlVTIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBSdXNzaWEgaW4gaW50ZXJuYXRpb25hbCBuZXdzIiwKICAgICB0ZXN0PVRSVUUpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CmBgYAoKIyMjIEFwcGxpY2F0aW9uIG7CsDMgOiBNYWNyb3JlZ2lvbiBzdWJ0b3BpYwoKU2FtZSBleGFtcGxlIGFwcGxpZWQgdG8gbWFjcm9yZWdpb24gOiB3aGF0IGlzIHRoZSBzaGFyZSBvZiB0aGUgc3VidG9waWMgRXVyb3BlYW4gVW5pb24gaW4gdGhlIHN1YnNhbXBsZSBuZXdzIHdoZXJlIGF0IGxlYXN0IG9uZSBtYWNyb3JlZ2lvbiBpcyBtZW50aW9ubmVkLgoKYGBge3J9CnJlcyA8LWhjX3llYXIgJT4lIGZpbHRlcihyZWdpb25zICE9ICJfbm9fIikgJT4lCndoby53aGF0KHdoYXQgPSAicmVnaW9ucyIsCiAgICAgc3VidG9wID0iT1JfRVUiLAogICAgIHRpdGxlID0gIlNoYXJlIG9mIEVVIGluIG1hY3JvcmVnaW9uYWwgbmV3cyIsCiAgICAgdGVzdD1UUlVFKQpyZXMkdGFibGUKcmVzJHBsb3RseQpzYXZlV2lkZ2V0KHdpZGdldD1yZXMkcGxvdGx5LAogICAgICAgICAgIGZpbGUgPSAid2lkZ2V0cy93aWRnZXRfd2hvX3doYXQuaHRtbCIsCiAgICAgICAgICAgc2VsZmNvbnRhaW5lZCA9IFQsCiAgICAgICAgICAgbGliZGlyPSJsaWIiKQpgYGAKCgoKIyMgV2hlbi5XaGF0CgojIyMgZnVuY3Rpb24KYGBge3J9CgojIyMjIC0tLS0tLS0tLS0tLS0tLS0gd2hlbi53aGF0IC0tLS0tLS0tLS0tLS0tLS0KIycgQHRpdGxlICB2aXN1YWxpemUgdmFyaWF0aW9uIG9mIHRoZSB0b3BpYyB0aHJvdWdoIHRpbWUKIycgQG5hbWUgd2hlbi53aGF0CiMnIEBkZXNjcmlwdGlvbiBjcmVhdGUgYSB0YWJsZSBvZiB2YXJpYXRpb24gb2YgdGhlIHRvcGljIGJ5IG1lZGlhCiMnIEBwYXJhbSB0ZXN0IDogdmlzdWFsaXplIHRlc3QgKFRSVUUpIG9yIHNhbGllbmNlIChGQUxTRSkKIycgQHBhcmFtIG1pbnNhbXAgOiBUaHJlc2hvbGQgb2Ygc2FtcGxlIHNpemUgcmVxdWVzdGVkIGZvciBzYWxpZW5jZSBjb21wdXRhdGlvbgojJyBAcGFyYW0gbWludGVzdCBzYW1wbGUgc2l6ZSBvZiBlc3RpbWF0ZSBmb3IgY2hpLXNxdWFyZSB0ZXN0IChkZWZhdWx0ID0gNSkKIycgQHBhcmFtIHRpdGxlIFRpdGxlIG9mIHRoZSBncmFwaGljCgoKd2hlbi53aGF0IDwtIGZ1bmN0aW9uIChoYyA9IGh5cGVyY3ViZSwKICAgICAgICAgICAgICAgICAgICAgICB3aGF0ID0gIndoYXQiLAogICAgICAgICAgICAgICAgICAgICAgIHN1YnRvcCA9IE5BLAogICAgICAgICAgICAgICAgICAgICAgIHRlc3QgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICBtaW5zYW1wID0gMjAsCiAgICAgICAgICAgICAgICAgICAgICAgbWludGVzdCA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiV2hlbiBpcyBzYWlkIFdoYXQgPyIpCnsKICAKICB0YWI8LWhjCiAgdGFiJHdoYXQ8LXRhYltbd2hhdF1dCmlmIChpcy5uYShzdWJ0b3ApKXt0YWIkd2hhdCA8LXRhYiR3aGF0ICE9Il9ub18ifWVsc2Uge3RhYiR3aGF0IDwtIHRhYiR3aGF0ID09IHN1YnRvcH0KIyAge3RhYiR3aGF0IDwtdGFiJHdoYXQgIT0iX25vXyJ9CiAgCiAgdGFiPC10YWJbLGxpc3QodHJpYWwgPSBzdW0obmV3cyksc3VjY2Vzcz1yb3VuZChzdW0obmV3cyp3aGF0KSwwKSksYnkgPSBsaXN0KHdoZW4pXQogIHJlZiA8LXJvdW5kKHN1bSh0YWIkc3VjY2Vzcykvc3VtKHRhYiR0cmlhbCksNCkKICB0YWIkbnVsbC52YWx1ZTwtcmVmCiAgCiAgdGFiPC10ZXN0Y2hpMih0YWJ0ZXN0PXRhYiwKICAgICAgICAgICAgICAgIG1pbnNhbXAgPSBtaW5zYW1wLAogICAgICAgICAgICAgICAgbWludGVzdCA9IG1pbnRlc3QpCiAgCiAgaWYgKHRlc3Q9PUZBTFNFKSB7dGFiJGluZGV4ID10YWIkc2FsaWVuY2UKICB0YWI8LXRhYlt0YWIkdHJpYWwgPiBtaW5zYW1wLF0KICBteWNvbDwtYnJld2VyLnBhbCg3LCJZbE9yUmQiKQogIH0gCiAgZWxzZSB7dGFiJGluZGV4PXRhYiRwLnZhbHVlCiAgdGFiPC10YWJbdGFiJHRyaWFsKnRhYiRudWxsLnZhbHVlPm1pbnRlc3QsXQogIG15Y29sPC1icmV3ZXIucGFsKDcsIlJkWWxCdSIpCiAgbXljb2xbNF08LSJsaWdodHllbGxvdyIKICB9CiAgCiAgCiAgcCA8LSBwbG90X2x5KHRhYiwKICAgICAgICAgICAgICAgeCA9IH5hcy5jaGFyYWN0ZXIod2hlbiksCiAgICAgICAgICAgICAgIHkgPSB+ZXN0aW1hdGUqMTAwLAogICAgICAgICAgICAgICBjb2xvcj0gfmluZGV4LAogICAgICAgICAgICAgICBjb2xvcnM9IG15Y29sLAogICAgICMgICAgICAgICAgaG92ZXJpbmZvID0gInRleHQiLAogICAgICAgICAgICAgICBob3ZlcnRlbXBsYXRlID0gfnBhc3RlKCdUaW1lOiAnLHdoZW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiBUb3RhbCBuZXdzICA6ICcsIHJvdW5kKHRyaWFsLDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICc8YnIgLz4gVG9waWMgbmV3cyA6ICcsIHJvdW5kKHN1Y2Nlc3MsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiAlIG9ic2VydmVkICA6ICcsIHJvdW5kKGVzdGltYXRlKjEwMCwyKSwnJScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJzxiciAvPiAlIGVzdGltYXRlZCA6ICcsIHJvdW5kKG51bGwudmFsdWUqMTAwLDIpLCclJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IFNhbGllbmNlIDogJywgcm91bmQoc2FsaWVuY2UsMiksICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGJyIC8+IHAudmFsdWUgOiAnLCByb3VuZChwLnZhbHVlLDQpKSwKICAgICAgICAgICAgICAgdHlwZSA9ICJiYXIiKSAgJT4lCiAgICBsYXlvdXQodGl0bGUgPSB0aXRsZSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiJSBuZXdzIiksCiAgICAgICAgICAgYmFybW9kZSA9ICdzdGFjaycpCiAgCiAgb3V0cHV0PC1saXN0KCJ0YWJsZSIgPSB0YWIsICJwbG90bHkiID1wKQogIAogIHJldHVybihvdXRwdXQpCiAgCn0KYGBgCgoKCiMjIyBBcHBsaWNhdG9uIG7CsDEgOiBDb3ZpZCBUb3BpYwoKQW4gZXhhbXBsZSBvZiBjb21wdXRhdGlvbiBvZiB0aGUgc2hhcmUgb2YgYSBub24gc3BhdGlhbCB0b3BpYyAoQ292aWQpIGluIHRoZSBmdWxsIHNhbXBsZSBvZiBuZXdzIGJ5IHdlZWsgZm9yIG9uZSBtZWRpYS4KCmBgYHtyfQpyZXMgPC0gaGNfd2VlayAlPiUgZmlsdGVyKHdobz09IkRFVV9zdWRkZXUiKSAlPiUKd2hlbi53aGF0KHdoYXQgPSAid2hhdCIsCiAgICAgdGl0bGUgPSAiU2hhcmUgb2YgQ292aWQtMTkgdG9waWMgaW4gbmV3cyBwdWJsaXNoZWQgYnkgU8O8ZGRldXRzY2hlIFplaXR1bmciLAogICAgIHRlc3Q9RkFMU0UpCgpyZXMkdGFibGUKcmVzJHBsb3RseQpgYGAKCgoKIyMjIEFwcGxpY2F0aW9uIG7CsDIgOiBTdGF0ZSBzdWJ0b3BpYwoKRXhhbXBsZSBvZiBhbmFseXNpcyBvZiB0aGUgc2hhcmUgb2YgbmV3cyBhYm91dCBSdXNzaWEgYW1vbmcgbmV3cyBtZW50aW9ubmluZyBvbmUgY291bnRyeSwgYnkgbW9udGgsIGZvciBMZSBGaWdhcm8uCgpgYGB7cn0KcmVzIDwtaGNfbW9udGggJT4lIGZpbHRlcihzdGF0ZXMgIT0gIl9ub18iKSAlPiUgIGZpbHRlcih3aG89PSJGUkFfZmlnYXJvIikgJT4lCndoZW4ud2hhdCh3aGF0ID0gInN0YXRlcyIsCiAgICAgc3VidG9wID0iUlVTIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBSdXNzaWEgaW4gaW50ZXJuYXRpb25hbCBuZXdzIHB1Ymxpc2hlZCBieSBMZSBGaWdhcm8iLAogICAgIHRlc3Q9VFJVRSkKcmVzJHRhYmxlCnJlcyRwbG90bHkKYGBgCgojIyMgQXBwbGljYXRpb24gbsKwMyA6IE1hY3JvcmVnaW9uIHN1YnRvcGljCgpFeGFtcGxlIG9mIGFuYWx5c2lzIG9mIHRoZSBzaGFyZSBvZiBuZXdzIGFib3V0IEV1cm9wZWFuIG5ld3MgYW1vbmcgbmV3cyBtZW50aW9uaW5nIG9uZSBtYWNyb3JlZ2lvbiwgYnkgeWVhciwgZm9yIER1bnlhLgoKYGBge3J9CnJlcyA8LWhjX3llYXIgJT4lIGZpbHRlcihyZWdpb25zICE9ICJfbm9fIikgJT4lICBmaWx0ZXIod2hvPT0iVFVSX2R1bnlhIikgJT4lCndoZW4ud2hhdCh3aGF0ID0gInJlZ2lvbnMiLAogICAgIHN1YnRvcCA9Ik9SX0VVIiwKICAgICB0aXRsZSA9ICJTaGFyZSBvZiBFVSBpbiBtYWNyb3JlZ2lvbmFsIG5ld3MgcHVibGlzaGVkIGJ5IER1bnlhIiwKICAgICB0ZXN0PVRSVUUpCnJlcyR0YWJsZQpyZXMkcGxvdGx5CnNhdmVXaWRnZXQod2lkZ2V0PXJlcyRwbG90bHksCiAgICAgICAgICAgZmlsZSA9ICJ3aWRnZXRzL3dpZGdldF93aG9fd2hhdC5odG1sIiwKICAgICAgICAgICBzZWxmY29udGFpbmVkID0gVCwKICAgICAgICAgICBsaWJkaXI9ImxpYiIpCmBgYA==